package com.lmt.ymcc.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.lmt.ymcc.domain.Course;
import com.lmt.ymcc.domain.CourseMarket;
import com.lmt.ymcc.domain.CourseOrder;
import com.lmt.ymcc.domain.CourseOrderItem;
import com.lmt.ymcc.dto.*;
import com.lmt.ymcc.exception.GlobalException;
import com.lmt.ymcc.feignclient.CourseFeignClient;
import com.lmt.ymcc.mapper.CourseOrderMapper;
import com.lmt.ymcc.result.JSONResult;
import com.lmt.ymcc.service.ICourseOrderItemService;
import com.lmt.ymcc.service.ICourseOrderService;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.lmt.ymcc.utils.AssertUtil;
import com.lmt.ymcc.utils.CodeGenerateUtils;
import com.lmt.ymcc.utils.LoginYmccContext;
import com.lmt.ymcc.utils.StrUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.client.producer.TransactionSendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import vo.Course2OrderInfoVo;
import vo.Course2OrderVo;

import java.util.*;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author AmazingXu
 * @since 2022-08-16
 */
@Service
@Slf4j
public class CourseOrderServiceImpl extends ServiceImpl<CourseOrderMapper, CourseOrder> implements ICourseOrderService {

    public static final String TOKEN_KEY = "token:%s+%s";

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    @Autowired
    private CourseFeignClient courseFeignClient;

    @Autowired
    private ICourseOrderItemService courseOrderItemService;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    // 课程购买下单
    @Override
    public String placeOrder(CourseOrderParamDto dto) {
        // 通过courseId查询数据
        Long loginId = LoginYmccContext.getLoginInfoDto().getId();
        String courseIds = StringUtils.join(dto.getCourseIds(), ",");
        String key = String.format(TOKEN_KEY, loginId, courseIds);
        Object token = redisTemplate.opsForValue().get(key);
        AssertUtil.isNotNull(token, "请勿重复下单");
        AssertUtil.isTrue(Objects.equals(token, dto.getToken().toString()), "非法请求");
        // 查询信息
        JSONResult info = courseFeignClient.info(courseIds);
        AssertUtil.isTrue(info.isSuccess(), "查询课程失败！！");
        Object data = info.getData();
        AssertUtil.isNotNull(data, "没有此课程！！");
        // 生成主订单信息
        Course2OrderInfoVo courseInfoVo = JSONObject.parseObject(JSON.toJSONString(data), Course2OrderInfoVo .class);
        List<Course2OrderVo> courseInfos = courseInfoVo.getCourseInfos();
        CourseOrder order = new CourseOrder();
        Date date = new Date();
        // 创建订单
        order.setCreateTime(date);
        order.setOrderNo(CodeGenerateUtils.generateOrderSn(loginId));
        order.setTotalAmount(courseInfoVo.getTotalAmount());
        order.setStatusOrder(CourseOrder.STATE_WAIT_PAY);
        order.setUserId(loginId);
        order.setPayType(dto.getPayType());
        // insert(order);
        // 生成子订单信息
        StringBuilder title = new StringBuilder();
        title.append("购买课程【");
        courseInfos.stream().forEach(vo->{
            Course course = vo.getCourse();
            CourseMarket courseMarket = vo.getCourseMarket();
            boolean isOnLine = course.getStatus() == Course.COURSE_ONLINE_STATUS;
            AssertUtil.isTrue(isOnLine,"课程状态非法！");
            CourseOrderItem item = new CourseOrderItem();
            item.setAmount(courseMarket.getPrice());
            item.setCount(1);
            item.setCreateTime(date);
            item.setCourseId(course.getId());
            item.setCourseName(course.getName());
            item.setCoursePic(course.getPic());
            item.setOrderNo(order.getOrderNo());
            //item.setOrderId(order.getId());
            //courseOrderItemService.insert(item);
            order.setTotalCount(order.getTotalCount() + 1);
            title.append(course.getName()).append("】，支付【").append(courseMarket.getPrice());
            order.getCourseOrderItems().add(item);
        });
        title.append("元】");
        order.setTitle(title.toString());
        // updateById(order);
        // 发送MQ消息
        Map<String, Object> map = new HashMap<>();
        map.put("loginId",loginId);
        map.put("courseId",courseIds);
        Order2PayParamDto  order2PayParamDto = new Order2PayParamDto(
                order.getTotalAmount(),
                dto.getPayType(),
                order.getOrderNo(),
                order.getUserId(),
                JSON.toJSONString(map),
                order.getTitle()
        );
        Message<String> message = MessageBuilder.withPayload(JSON.toJSONString(order2PayParamDto)).build();
        // 发送事务消息
        TransactionSendResult sendResult = rocketMQTemplate.sendMessageInTransaction(
                "TxOrder2PayGroup",
                "order-topic:payorder-tags",
                message,
                order
        );
        // 执行本地事务
        log.info("执行本地事务开始");
        LocalTransactionState localTransactionState = sendResult.getLocalTransactionState();
        SendStatus sendStatus = sendResult.getSendStatus();
        log.info("执行本地事务结束");
        // 判断事务是否成功
        if (localTransactionState != LocalTransactionState.COMMIT_MESSAGE || sendStatus != SendStatus.SEND_OK) {
            throw new GlobalException("下单失败，请重新订单");
        }
        // 删除token
        redisTemplate.delete(key);
        // 如果订单超时未支付
        try {
            Message<String> delayMessage = MessageBuilder.withPayload(order.getOrderNo()).build();
            SendResult syncSend = rocketMQTemplate.syncSend(
                    "cancel-order-topic:paytimeout-tags",
                    delayMessage,
                    3000,
                    4  //30秒
            );
            SendStatus sendSendStatus = syncSend.getSendStatus();
            if(sendSendStatus != SendStatus.SEND_OK){
                // 人工介入
            }
        } catch (Exception e) {
            e.printStackTrace();
            // 人工介入
        }


        return order.getOrderNo();
    }

    // 保存订单信息（主订单和子订单）
    @Override
    public void savaOrderAndItem(CourseOrder courseOrder) {
        CourseOrder courseOrderTemp = selectByOrderNo(courseOrder.getOrderNo());
        AssertUtil.isNull(courseOrderTemp, "请勿重复下单，订单已存在");
        insert(courseOrder);
        for (CourseOrderItem courseOrderItem : courseOrder.getCourseOrderItems()) {
            courseOrderItem.setOrderId(courseOrder.getId());
            courseOrderItemService.insert(courseOrderItem);
        }
    }

    @Override
    public CourseOrder  selectByOrderNo(String orderNo) {
        Wrapper<CourseOrder> wrapper = new EntityWrapper<>();
        wrapper.eq("order_no", orderNo);
        return selectOne(wrapper);
    }

    @Override
    public void updateOrderByPayNotify(AliPayMessageDto dto) {
        CourseOrder courseOrder = selectByOrderNo(dto.getOrderNo());
        if(courseOrder.getStatusOrder() == CourseOrder.STATE_WAIT_PAY){
            courseOrder.setStatusOrder(CourseOrder.STATE_SUCCESS);
            courseOrder.setUpdateTime(new Date());
            updateById(courseOrder);
        }else{
            // 人工处理
        }
    }

    @Override
    public void cancelOrderByPayTimeOut(String orderNo) {
        CourseOrder courseOrder = selectByOrderNo(orderNo);
        if(courseOrder == null){
            return;
        }
        // 只有是待支付才能取消
        boolean isWaitPay = courseOrder.getStatusOrder() == CourseOrder.STATE_WAIT_PAY;
        if(!isWaitPay){
            // 如果是支付了，就不要执行定时任务
            return;
        }
        courseOrder.setStatusOrder(CourseOrder.STATE_CANCEL);
        courseOrder.setUpdateTime(new Date());
        updateById(courseOrder);
    }

    // 秒杀支付接口
    @Override
    public String killPlaceOrder(KillCourseOrderParamDto dto) {
        // 通过courseId查询数据
        Long loginId = LoginYmccContext.getLoginInfoDto().getId();
        PreCourseOrder preCourseOrder = (PreCourseOrder) redisTemplate.opsForValue().get(dto.getOrderNo());
        String key = String.format(TOKEN_KEY, loginId, preCourseOrder.getCourseId());
        Object token = redisTemplate.opsForValue().get(key);
        AssertUtil.isNotNull(token, "token不存在");
        AssertUtil.isTrue(Objects.equals(token, dto.getToken().toString()), "非法请求");
        // 生成主订单信息
        CourseOrder order = new CourseOrder();
        Date date = new Date();
        // 创建订单
        order.setCreateTime(date);
        order.setOrderNo(preCourseOrder.getOrderNo());
        order.setTotalAmount(preCourseOrder.getTotalAmount());
        order.setStatusOrder(CourseOrder.STATE_WAIT_PAY);
        order.setUserId(loginId);
        order.setPayType(dto.getPayType());
        order.setTitle("课程【" + preCourseOrder.getCourseName() + "】，支付金额【"+ preCourseOrder.getTotalAmount() +"】元");
        // 生成子订单信息
        CourseOrderItem item = new CourseOrderItem();
        item.setAmount(preCourseOrder.getTotalAmount());
        item.setCount(1);
        item.setCreateTime(date);
        item.setCourseId(preCourseOrder.getCourseId());
        item.setCourseName(preCourseOrder.getCourseName());
        item.setCoursePic(preCourseOrder.getCoursePic());
        item.setOrderNo(order.getOrderNo());
        order.setTotalCount(1);
        order.getCourseOrderItems().add(item);
        // 发送MQ消息
        Map<String, Object> map = new HashMap<>();
        map.put("loginId",loginId);
        map.put("courseId",preCourseOrder.getCourseId());
        Order2PayParamDto  order2PayParamDto = new Order2PayParamDto(
                order.getTotalAmount(),
                dto.getPayType(),
                order.getOrderNo(),
                order.getUserId(),
                JSON.toJSONString(map),
                order.getTitle()
        );
        Message<String> message = MessageBuilder.withPayload(JSON.toJSONString(order2PayParamDto)).build();
        // 发送事务消息
        TransactionSendResult sendResult = rocketMQTemplate.sendMessageInTransaction(
                "TxOrder2PayGroup",
                "order-topic:payorder-tags",
                message,
                order
        );
        // 执行本地事务
        log.info("执行本地事务开始");
        LocalTransactionState localTransactionState = sendResult.getLocalTransactionState();
        SendStatus sendStatus = sendResult.getSendStatus();
        log.info("执行本地事务结束");
        // 判断事务是否成功
        if (localTransactionState != LocalTransactionState.COMMIT_MESSAGE || sendStatus != SendStatus.SEND_OK) {
            throw new GlobalException("下单失败，请重新订单");
        }
        // 删除token
        redisTemplate.delete(key);
        // 如果订单超时未支付
        try {
            Message<String> delayMessage = MessageBuilder.withPayload(order.getOrderNo()).build();
            SendResult syncSend = rocketMQTemplate.syncSend(
                    "cancel-order-topic:paytimeout-tags",
                    delayMessage,
                    3000,
                    4  //30秒
            );
            SendStatus sendSendStatus = syncSend.getSendStatus();
            if(sendSendStatus != SendStatus.SEND_OK){
                // 人工介入
            }
        } catch (Exception e) {
            e.printStackTrace();
            // 人工介入
        }
        return order.getOrderNo();
    }
}
